/*
 * @Author: kimsoso
 * @Date: 2022-01-05 18:55:23
 * @LastEditTime: 2022-03-14 16:51:05
 * @LastEditors: Please set LastEditors
 * @Description: 全局配置处理
 * @FilePath: /file-sync/config/config.go
 */
package config

import (
	"context"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"gitee.com/kimsoso/go-utils/utils"
	"github.com/fsnotify/fsnotify"
	"gopkg.in/yaml.v3"
)

// 配置文件结构体
type Config struct {
	sync.RWMutex
	RootDir         string `yaml:"rootDir"`         //根目录
	NodesFile       string `yaml:"nodesFile"`       //限制协程数量
	AutoNodes       bool   `yaml:"autoNodes"`       //是否使用自动探测周边NODE，如开启，则每5分钟探测活跃Nodes
	AnInterval      int    `yaml:"anInterval"`      //自动探测活跃节点的间隔, 秒为单位
	Log             bool   `yaml:"log"`             //是否需要日志
	Threads         int    `yaml:"threads"`         //限制协程数量
	Interval        string `yaml:"interval"`        //重试间隔
	RoutineInterval string `yaml:"routineInterval"` //协程的重试等待时间
	Bandwidth       string `yaml:"bandwidth"`       //限制带宽
	Expiration      string `yaml:"expiration"`      //数据过期时间
	MaxRetry        int    `yaml:"maxRetry"`        //一个数据块最多的重试次数
	// HttpPort        int    `yaml:"httpPort"`        //通讯tcp 端口
	DataPort int   `yaml:"dataPort"` //数据端口
	LastTime int64 `yaml:"lastTime"` //最后存活时间

	bandwidth float64
}

//"2006-01-02 15:04:05"

var (
	svrConfig  *Config
	onceConfig sync.Once
)

func init() {
	// 设置默认配置
	setDefaultConfiguration()
	// 读取配置文件
	loadSvrConfFiles()
	// 设置日志输出方式stdout, file
	setSystemLog()

	c := GetConfig()
	os.MkdirAll(DirCmds, os.ModePerm)
	os.MkdirAll(c.RootDir, os.ModePerm)
}

func WatchConfs(ctx context.Context) *Watch {
	c := GetConfig()
	watch, err := NewConfsWatch(PathOfConfig, c.NodesFile)
	if err != nil {
		panic(err)
	}

	watch.WatchConfs(ctx, func(act fsnotify.Op, filePath string) {

		if filePath == PathOfConfig {
			ReloadConfig()
		}

		// 自动监测情况下，不需要监视配置文件
		if !c.AutoNodes {
			if filePath == c.NodesFile {
				ReloadNodes()
			}
		}
	})

	return watch
}

func setDefaultConfiguration() {
	_, err := os.Stat(PathOfConfig)
	if os.IsNotExist(err) {
		yaml :=
			`rootDir: "files/" #根目录
nodesFile: "nodes.yaml" #节点文件
autoNodes: true #是否使用自动探测周边NODE, 如开启, 则每5分钟探测活跃Nodes
anInterval: 120 #自动探测活跃节点的间隔, 秒为单位
log: true #是否记录日志
threads: 10 #协程生成数量
interval: 1s #普通协程休眠时间
routineInterval: 10ms #下载协程休眠时间
bandwidth: "1m" #下载协程限速 xxxk, xxxm
dataPort: 9111 #数据端口`

		utils.WriteFile(PathOfConfig, []byte(yaml), os.ModePerm)
	}
}

func loadSvrConfFiles() {
	conf := GetConfig()
	if conf == nil {
		panic("load config file error")
	}
	nodes := GetNodes()
	if nodes == nil {
		panic("load nodes file error")
	} else if len(nodes) == 0 && !conf.AutoNodes {
		panic("at least need 2 nodes")
	}
}

// 得到配置文件
func GetConfig() *Config {
	onceConfig.Do(func() {
		ReloadConfig()
	})
	return svrConfig
}

//重新加载配置文件
func ReloadConfig() {
	fileContent, _ := ioutil.ReadFile(PathOfConfig)
	config := Config{}
	err := yaml.Unmarshal(fileContent, &config)
	if err == nil {
		svrConfig = &config
		svrConfig.setBandwidth()
		DirFiles = svrConfig.RootDir
	} else {
		log.Println("load config file error:", err)
	}
}

//存入磁盘
func (c *Config) SaveToDisk() error {
	c.Lock()
	defer c.Unlock()

	fileContent, err := yaml.Marshal(c)
	if err != nil {
		return err
	}
	return utils.WriteFile(PathOfConfig, fileContent, os.ModePerm)
}

//访问节点间隔时间
func (c *Config) Sleep() {
	drt, _ := time.ParseDuration(c.Interval)
	time.Sleep(drt)
}

//块数据下载间隔时间
func (c *Config) SleepForRoutine() {
	drt, _ := time.ParseDuration(c.RoutineInterval)
	time.Sleep(drt)
}

// 得到限速的浮点数值以k byte为单位
func (c *Config) setBandwidth() {
	var val float64 = 0
	if c.Bandwidth == "0" {
		c.bandwidth = 0
		return
	}
	var err error
	val, err = strconv.ParseFloat(c.Bandwidth[:len(c.Bandwidth)-1], 64)
	if err != nil {
		c.bandwidth = 0
		return
	}

	lastChar := strings.ToLower(c.Bandwidth[len(c.Bandwidth)-1:])
	switch lastChar {
	case "m":
		val *= 1024
	default:
		panic("bandwidth only accept k or m")
	}
	c.bandwidth = val
}

func (c *Config) GetBandwidth() float64 {
	return c.bandwidth
}
